﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Qy.Core;
using Qy.Scenario;
using Qy.Web.Authorize.Common;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Text.Json;

namespace Qy.Web.Authorize;

public static class JwtHelper
{
    public static string CreateJwt(TokenModelJwt model)
    {
        var authTime = DateTime.Now;
        var expiresAt = authTime.AddMinutes(model.Expires);
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(model.Secret);
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.PrimarySid,model.UserId.ToString()),
            new Claim(ClaimTypes.PrimaryGroupSid,model.UserGid.ToString()),
            new Claim(ClaimTypes.Name,model.UserName),
            new Claim(ClaimTypes.UserData, JsonSerializer.Serialize(model))
        };
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(claims),
            Issuer = model.Issuer,
            Audience = model.Audience,
            IssuedAt = authTime,
            Expires = expiresAt,
            TokenType = "Bearer",
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
        };
        var httpContext = App.HttpContext;
        ICacheManager cacheManager = httpContext.RequestServices.GetService<ICacheManager>();
        cacheManager.Set(CacheConst.CACHE_KEY_USER_LOGIN + model.UserId, model.UserName, TimeSpan.FromMinutes(model.Expires));
        return tokenHandler.WriteToken(tokenHandler.CreateToken(tokenDescriptor));
    }


    public static TokenValidationParameters ValidParameters()
    {
        TokenModelJwt jwtSettings = new();
        AppSettings.Bind("Jwt", jwtSettings);
        if (jwtSettings == null || jwtSettings.Secret.IsEmpty())
        {
            throw new Exception("Jwt设置获取失败");
        }
        var key = Encoding.ASCII.GetBytes(jwtSettings.Secret);
        var tokenDescriptor = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidIssuer = jwtSettings.Issuer,
            ValidAudience = jwtSettings.Audience,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateLifetime = true,//是否验证Token有效期，使用当前时间与Token的Claims中的NotBefore和Expires对比
            ClockSkew = TimeSpan.FromSeconds(30),
            RequireExpirationTime = true,//过期时间
        };
        return tokenDescriptor;
    }


    public static TokenModelJwt SerializeJwt(string jwtStr)
    {
        var jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(jwtStr);
        return JsonSerializer.Deserialize<TokenModelJwt>(jwtToken.Payload.SerializeToJson());
    }

    /// <summary>
    /// 获取登录用户 判断TOKEN是否存在
    /// </summary>
    /// <returns></returns>
    public static TokenModelJwt GetLoginUser()
    {
        try
        {
            var httpContext = App.HttpContext;
            string token = httpContext.GetToken();
            string userData = ParseToken(token)?.FirstOrDefault(x => x.Type == ClaimTypes.UserData).Value;
            if (userData == null) return null;
            TokenModelJwt tokenModelJwt = JsonSerializer.Deserialize<TokenModelJwt>(userData);
            string userName = httpContext.RequestServices.GetService<ICacheManager>().GetValue(CacheConst.CACHE_KEY_USER_LOGIN + tokenModelJwt?.UserId);
            return userName == null ? null : tokenModelJwt;
        }
        catch
        {
            return null;
        }
    }


    /// <summary>
    /// 从令牌中获取数据声明
    /// </summary>
    /// <param name="token">令牌</param>
    /// <returns></returns>
    public static IEnumerable<Claim> ParseToken(string token)
    {
        try
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var validateParameter = ValidParameters();
            token = token.Replace("Bearer ", "");
            tokenHandler.ValidateToken(token, validateParameter, out SecurityToken validatedToken);
            var jwtToken = tokenHandler.ReadJwtToken(token);
            return jwtToken.Claims;
        }
        catch
        {
            return null;
        }
    }


}

/// <summary>
/// 令牌对象
/// </summary>
public class TokenModelJwt
{
    /// <summary>
    /// 用户Id
    /// </summary>
    public int UserId { get; set; }
    /// <summary>
    /// 角色ID
    /// </summary>
    public int UserGid { get; set; }
    /// <summary>
    /// 用户名称
    /// </summary>
    public string UserName { get; set; }
    /// <summary>
    /// 发行人
    /// </summary>
    public string Issuer { get; set; }
    /// <summary>
    /// 观众
    /// </summary>
    public string Audience { get; set; }
    /// <summary>
    /// 秘钥
    /// </summary>
    public string Secret { get; set; }
    /// <summary>
    /// 过期时间
    /// </summary>
    public int Expires { get; set; }

}